//
//  SFCTextFileDiff.h
//  SVNForCocoa
//
//  Created by Jeremy Pereira on 12/12/2013.
//  Copyright (c) 2013 Jeremy Pereira. All rights reserved.
//
/*!
 *    @file
 *    @brief DEclarations associated with a diff structure
 */

#import <Foundation/Foundation.h>
#import "SFCObject.h"
#import "SFCLineConsumer.h"


/*!
 *    @brief Diff type tells us whether a line is an addition, deletion or no 
 *           change.
 *    @todo Document the members.
 */
enum SFCDiffType
{
    /*!
     *    @brief Line was added in the right file.
     */
    SFC_DIFF_ADDITION = '+',
    /*!
     *    @brief Line was deleted from the right file.
     */
    SFC_DIFF_DELETION = '-',
    /*!
     *    @brief Line remained unchanged across the diff.
     */
    SFC_DIFF_IDENTITY = ' '
};

/*!
 *    @brief Convenience superclass for things that parse lines from the diff
 *           file.
 *
 *    Provides common functionality, like the owner so that stacks of parsers
 *    can be made.
 *
 *    Conforms to NSFastEnumeration because all of our objects that can parse
 *    files have children.  It's left abstract in this super class though.
 *
 */
@interface SFCDiffFileParser : SFCObject <NSFastEnumeration, SFCLineConsumer>

/*!
 *    @brief Designated initialiser.
 *
 *    -init is equivalent of this with a nil owner.
 *
 *    @param owner Object that owns this parser.
 *
 *    @return A new parser.
 */
-(id) initWithOwner: (id<SFCLineConsumer>) owner;

/*!
 *    @brief The owner of this parser.
 */
@property (nonatomic, readonly, weak) id<SFCLineConsumer> owner;

@end



@class SFCTextFileDiff;

typedef enum SFCDiffType SFCDiffType;
/*!
 *    @brief A diff line.
 *
 *    Each diff line is a string of text and a property which tells us if it is
 *    an addition, deletion or a no change.
 */
@interface SFCDiffLine : SFCObject
/*!
 *    @brief The type of difference, no change, deletion or addition.
 */
@property (readonly, nonatomic, assign) SFCDiffType diffType;
/*!
 *    @brief The text of the line.
 */
@property (readonly, nonatomic, strong) NSString* text;

/*!
 *    @brief The line number from the "before" version of the file.
 *
 *    If it didn't have a line number i.e. is an insertion, we use NSNotFound.
 */
@property (nonatomic, readonly, assign) NSInteger leftLineNumber;
/*!
 *    @brief The line number from the "after" version of the file.
 *
 *    If it didn't have a line number i.e. is a deletion, we use NSNotFound.
 */
@property (nonatomic, readonly, assign) NSInteger rightLineNumber;

@end

/*!
 *    @brief A single hunk of a diff.
 *
 *    @details A hunk appears in a diff file something like this.
 *
 *    @code
 *@@ -624,7 +624,7 @@
 *
 * -(IBAction) testParseArray: (id) sender
 * {
 *-	RMJsonParser* parser = [[RMJsonParser alloc] init];
 *+	RMJsonJPParser* parser = [[RMJsonJPParser alloc] init];
 * 	NSString* testString = @"[1, 2, \"foo\", 3]";
 * 	@try
 * 	{
 *    @endcode
 *
 *    The SFCDiffHunk represents all of this, si it has a "header" telling us 
 *    the line ranges and a number of lines, each beginning with a space, a '+' 
 *    or a '-'.  The first character tells us the if the line is unchanged, 
 *    added or deleted.
 *
 *    This class implements NSFastEnumeration to iterate over the lines in the
 *    hunk.
 */
@interface SFCDiffHunk : SFCDiffFileParser

/*!
 *    @brief Number of lines in the hunk.
 */
@property (nonatomic, readonly, assign) size_t lineCount;

/*!
 *    @brief Get the line at the given index.
 *
 *    Will throw a range exception if you attempt to index anything outside the
 *    range [0 .. lineCount)
 *
 *    @param index Index of line to get.
 *
 *    @return The line at the given index.
 */
-(SFCDiffLine*) lineAtIndex: (size_t) index;

/*!
 *    @brief Range of lines in the left file covered by this hunk.
 */
@property (nonatomic, assign) NSRange leftRange;
/*!
 *    @brief Range of lines in the right file covered by this hunk.
 */
@property (nonatomic, assign) NSRange rightRange;
/*!
 *    @brief The header of the hunk reconstituted.
 */
@property (nonatomic, readonly, copy) NSString* header;

/*!
 *    @brief The index of the hunk in the diff.
 */
@property (nonatomic, readonly, assign) size_t sequenceNumber;

@end

/*!
 *    @brief Text file differences.
 *
 *    This models the set of differences between two text files.  It's created
 *    by parsing the normal output of svn diff.  This is a list of humks,
 *    where each humk has a header telling us the line range in the left and
 *    right files.  Then there is a list of lines.
 *
 *    This class implements NSFastEnumeration to iterate over the hunks and
 *    SFCLineConsumer to create hunks.
 */
@interface SFCTextFileDiff : SFCDiffFileParser

/*!
 *    @brief Number of hunks in this diff.
 */
@property (nonatomic, readonly, assign) size_t hunkCount;

/*!
 *    @brief Get the hunk at the given index.
 *
 *    Will throw a range exception if you attempt to index anything outside the
 *    range [0 .. hunkCount)
 *
 *    @param index Index of hunk to get.
 *
 *    @return The hunk at the given index.
 */
-(SFCDiffHunk*) hunkAtIndex: (size_t) index;

/*!
 *    @brief The name of the file that this represents a diff of.
 */
@property (nonatomic, copy) NSString* fileName;

@end

/*!
 *    @brief Represents a collection of differences from multiple files.
 *
 *    This will contain one object if it is a diff on a file, but multiple 
 *    objects (one per file) if it is a diff on a directory.
 */
@interface SFCDiffCollection : SFCDiffFileParser
/*!
 *    @brief Number of diffs in this collection.
 */
@property (nonatomic, readonly, assign) size_t diffCount;

/*!
 *    @brief Get the diff at the given index.
 *
 *    Will throw a range exception if you attempt to index anything outside the
 *    range [0 .. diffCount)
 *
 *    @param index Index of diff to get.
 *
 *    @return The diff at the given index.
 */
-(SFCTextFileDiff*) diffAtIndex: (size_t) index;

/*!
 *    @brief Get a stream to write diffs to.
 *
 *    Thisis an output stream that is consumed by this diff to parse a diff file
 *    into hunks.  Writes to the stream get parsed as they go through.  If a
 *    write results in something that can't be parsed as a diff, -1 will be
 *    returned and the streamError will be set.
 *
 *    Data written to the stream must be encoded in UTF-8.
 *
 *    @return An output stream for writing the diff to.
 */
@property (nonatomic, readonly, strong) NSOutputStream* outputStream;

@end
